grammar crn;

@header {
package odesimulation;

import java.util.HashMap;
}

reactionset	
locals [
ArrayList<Reaction> reactions = new ArrayList<Reaction>(),
HashMap<String, Enzyme> enzymes = new HashMap<String, Enzyme>(),
ArrayList<String> enzymenames = new ArrayList<String>(),
ArrayList<String> symbols = new ArrayList<String>(),
ArrayList<String> symbolList = new ArrayList<String>(),
ArrayList<ArrayList<Double>> Kmvalues = new ArrayList<ArrayList<Double>>(),
ArrayList<ArrayList<Double>> kivalues = new ArrayList<ArrayList<Double>>()
] : decl matrix ((reaction|enzreaction))+;

decl : enzdecl reacdecl;

enzdecl
@after{ for(int i = 0; i<$e.size(); i++) { 
			if($e.get(i)!= null)
				$reactionset::enzymes.put($e.get(i).getText(), new Enzyme());
				$reactionset::enzymenames.add($e.get(i).getText());
		}} : 'enzymes:' e+=ENZYME+;

reacdecl : 'products:' iddecl+;

iddecl : ID {if ( !$reactionset::symbolList.contains($ID.text) ) { $reactionset::symbolList.add($ID.text); } };

matrix : km ki;

km 
@after{ for(int i = 0; i < $enzlist.size(); i++)
			{
			  $reactionset::Kmvalues.add($enzlist.get(i)!=null?$enzlist.get(i).values:null);
			}
		}: 'K_m[' NUM '][' NUM ']' ':' '{' enzlist+=enzval+ '}' ;

ki
@after{ for(int i = 0; i < $enzlist.size(); i++)
			{
			  $reactionset::kivalues.add($enzlist.get(i)!=null?$enzlist.get(i).values:null);
			}
		}: 'k_i[' NUM '][' NUM ']' ':' '{' enzlist+=enzval+ '}';

enzval 
locals[
ArrayList<Double> values = new ArrayList<Double>()
]
@after{ 
			
			for(int i = 0; i < $el.size(); i++)
				{
			  	$enzval::values.add( ($el.get(i)!=null?Double.parseDouble($el.get(i).getText()):null) );
				}
		}
: '{' el+=VALUE+ '}'; 

reaction
locals [
ArrayList<String> reactants = new ArrayList<String>(),
ArrayList<String> products = new ArrayList<String>()]
@after{ $reactionset::reactions.add(new Reaction($reactants,$products,Double.parseDouble($v1.text), Double.parseDouble($v2.text))); }
	: leftside '<==>' rightside '[' 'k+' '=' v1=VALUE ';' 'k-' '=' v2=VALUE ']';
leftside	: | id {$reaction::reactants.add($id.text);}| i1=id '+' i2=id {$reaction::reactants.add($i1.text);$reaction::reactants.add($i2.text);};
rightside	: | id {$reaction::products.add($id.text);} | i1=id '+' i2=id {$reaction::products.add($i1.text);$reaction::products.add($i2.text);};

enzreaction
locals [
String reactants = "",
String enzyme = "",
String enzleft = "",
String enzright = "",
ArrayList<String> products = new ArrayList<String>()]
@after{
	if($enzleft.equals($enzright)){
		$enzyme = $enzleft;
 		$reactionset::reactions.add(new EnzymaticReaction($reactants,$enzyme,$products)); 
		Enzyme myEnz;
		if($reactionset::enzymes.containsKey($enzyme)){
			myEnz = $reactionset::enzymes.get($enzyme);
		} else {
			myEnz = new Enzyme();
			$reactionset::enzymes.put($enzyme,myEnz);
			System.err.println("WARNING: unknown enzyme");
		}
		if(!myEnz.Kms.containsKey($reactants)){
			myEnz.Kms.put($reactants,$reactionset::Kmvalues.get($reactionset::enzymenames.indexOf($enzyme)).get($reactionset::symbolList.indexOf($reactants)));
			myEnz.kis.put($reactants,$reactionset::kivalues.get($reactionset::enzymenames.indexOf($enzyme)).get($reactionset::symbolList.indexOf($reactants)));
		}
	} else {
		System.err.println("Enzyme mismatch: "+$enzleft+" "+$enzright);
	}
}
 : enzleftside '==>' enzrightside ;

enzleftside
	: (id '+' ENZYME | ENZYME '+' id) {$enzreaction::enzleft = $ENZYME.text;$enzreaction::reactants = $id.text;};
enzrightside

	: (ENZYME | ENZYME '+' id {$enzreaction::products.add($id.text);}| ENZYME '+' p1=id '+' p2=id {$enzreaction::products.add($p1.text);$enzreaction::products.add($p2.text);}) {$enzreaction::enzright = $ENZYME.text;};

id 	: ID {if ( !$reactionset::symbols.contains($ID.text) ) { $reactionset::symbols.add($ID.text); } } ;
ID	: [a-zA-Z] ;
ENZYME	: 'E'NUM;
NUM	: [0-9]+;
VALUE : NUM+ ('.')? NUM* ('e'|'E')? ('-' NUM)? NUM*;
COMMENT : '#' (~'\n')* '\n' -> skip; 
WS	: [ \r\t\n]+ -> skip;
